package my.edu.model.information.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import my.edu.common.constant.MessageConstant;
import my.edu.common.domain.PageDTO;
import my.edu.common.domain.PageVO;
import my.edu.common.exception.BillsException;
import my.edu.common.exception.CategoryException;
import my.edu.common.utils.PageUtils;
import my.edu.constant.BillsType;
import my.edu.model.User.entity.User;
import my.edu.model.information.entity.*;
import my.edu.model.information.entity.VO.CustomerVO;
import my.edu.model.information.entity.VO.SupplierVO;
import my.edu.model.information.entity.dto.SupplierDTO;
import my.edu.model.information.entity.dto.SupplierSearchDTO;
import my.edu.utils.ChildrenLoader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import my.edu.model.information.mapper.SupplierMapper;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SupplierServiceImpl extends ServiceImpl<SupplierMapper, Supplier> implements ISupplierService {

    @Autowired
    private ISupplierCategoryService supplierCategoryService;

    @Autowired
    private ISupplierPayableBalanceDetailService supplierPayableBalanceDetailService;

    @Override
    public void savenew(SupplierDTO supplierDTO) {
        //检查类别
//        SupplierCategory category = supplierCategoryService.getById(supplierDTO.getSupplierCategoryId());
//        if (category == null || category.getStatus().equals(0)) {
//            throw new CategoryException(MessageConstant.CATEGORIES_NOT_AVAILABLE);
//        }

        Supplier supplier = BeanUtil.copyProperties(supplierDTO, Supplier.class);
        supplier.setStatus(1);
        supplier.setPayableBalance(BigDecimal.ZERO);
        save(supplier);
    }

    @Override
    public PageVO<SupplierVO> listAll(PageDTO pageDTO, SupplierSearchDTO supplierSearchDTO) {
        MPJLambdaWrapper<Supplier> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(Supplier.class, SupplierVO.class)
                .selectAs(User::getName, SupplierVO::getSalespersonName)
                .leftJoin(User.class, User::getId, Supplier::getSalespersonId)
                .like(StrUtil.isNotBlank(supplierSearchDTO.getSupplierName()), Supplier::getSupplierName, supplierSearchDTO.getSupplierName())
                .like(StrUtil.isNotBlank(supplierSearchDTO.getSalespersonName()), User::getName, supplierSearchDTO.getSalespersonName())
                .like(StrUtil.isNotBlank(supplierSearchDTO.getPhone()), Supplier::getPhone, supplierSearchDTO.getPhone())
                .like(StrUtil.isNotBlank(supplierSearchDTO.getQqWechat()), Supplier::getQqWechat, supplierSearchDTO.getQqWechat());

        // 1. 分页查主表 + 联表字段
        Page<SupplierVO> supplierVOPage = baseMapper.selectJoinPage(
                new Page<>(pageDTO.getPage(), pageDTO.getSize()),
                SupplierVO.class,
                wrapper
        );

        if (CollUtil.isNotEmpty(supplierVOPage.getRecords())) {
            ChildrenLoader.loadAndFill(
                    supplierVOPage.getRecords(),
                    SupplierVO::getId,
                    ids -> supplierPayableBalanceDetailService.list(
                            Wrappers.<SupplierPayableBalanceDetail>lambdaQuery()
                                    .in(SupplierPayableBalanceDetail::getSupplierId, ids)
                                    .orderByDesc(SupplierPayableBalanceDetail::getId)
                    ),
                    SupplierPayableBalanceDetail::getSupplierId,
                    SupplierVO::setSupplierPayableBalanceDetails
            );

        }

        return PageUtils.toPage(supplierVOPage);
    }

    @Override
    public SupplierVO getVOById(String id) {
        MPJLambdaWrapper<Supplier> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(Supplier.class, SupplierVO.class)
                // .selectAs(SupplierCategory::getCategoryName, SupplierVO::getSupplierCategoryName)
                .selectAs(User::getName, SupplierVO::getSalespersonName)
                .selectCollection(SupplierPayableBalanceDetail.class, SupplierVO::getSupplierPayableBalanceDetails)
                //.leftJoin(SupplierCategory.class, SupplierCategory::getId, Supplier::getSupplierCategoryId)
                .leftJoin(User.class, User::getId, Supplier::getSupplierCategoryId)
                .leftJoin(SupplierPayableBalanceDetail.class, SupplierPayableBalanceDetail::getSupplierId, Supplier::getId)
                .eq(Customer::getId, id);
        SupplierVO supplierVO = baseMapper.selectJoinOne(SupplierVO.class, wrapper);
        BigDecimal balance = new BigDecimal(0);
        for (SupplierPayableBalanceDetail supplierPayableBalanceDetail : supplierVO.getSupplierPayableBalanceDetails()) {
            String billsType = supplierPayableBalanceDetail.getBillsType();
            if (billsType.equals(BillsType.PURCHASE)) {
                balance = balance.add(supplierPayableBalanceDetail.getPayableBalance());
            } else if (billsType.equals(BillsType.PURCHASERETURN)) {
                balance = balance.subtract(supplierPayableBalanceDetail.getPayableBalance());
            }
        }
        supplierVO.setPayableBalance(balance);
        return supplierVO;
    }

    @Override
    public void updateByDTO(SupplierDTO supplierDTO) {
        Supplier supplier = BeanUtil.copyProperties(supplierDTO, Supplier.class);
        updateById(supplier);
    }

    // 添加进货欠款记录
    @Override
    @Transactional
    public void addPayableBalanceDetails(SupplierPayableBalanceDetail supplierPayableBalanceDetail) {
        supplierPayableBalanceDetailService.save(supplierPayableBalanceDetail);
        Map<Long, BigDecimal> collect = Map.of(supplierPayableBalanceDetail.getSupplierId(), supplierPayableBalanceDetail.getPayableBalance());
        addPayableBalance(collect);
    }

    @Override
    public void addPayableBalanceDetails(List<SupplierPayableBalanceDetail> supplierPayableBalanceDetailList) {
        List<SupplierPayableBalanceDetail> list = supplierPayableBalanceDetailList.stream().filter(i -> i.getPayableBalance().compareTo(BigDecimal.ZERO) > 0).toList();
        if (list.isEmpty()) return;
        supplierPayableBalanceDetailService.saveBatch(list);
        Map<Long, BigDecimal> collect = supplierPayableBalanceDetailList.stream().collect(Collectors.toMap(
                SupplierPayableBalanceDetail::getSupplierId,
                SupplierPayableBalanceDetail::getPayableBalance
        ));
        addPayableBalance(collect);
    }

    //去除进货欠款记录
    @Override
    @Transactional
    public void removePayableBalanceDetails(List<Long> ids, String billsType) {
        if (ids == null || ids.isEmpty()) return;
        LambdaQueryWrapper<SupplierPayableBalanceDetail> wrapper =
                Wrappers.<SupplierPayableBalanceDetail>lambdaQuery()
                .eq(SupplierPayableBalanceDetail::getBillsType, billsType)
                .in(SupplierPayableBalanceDetail::getBillId, ids);
        List<SupplierPayableBalanceDetail> list = supplierPayableBalanceDetailService.list();
        Map<Long, BigDecimal> collect = list.stream().collect(Collectors.toMap(
                SupplierPayableBalanceDetail::getSupplierId,
                SupplierPayableBalanceDetail::getPayableBalance,
                BigDecimal::add // 合并函数，将相同的 supplierId 的 payableBalance 相加
        ));
        subPayableBalance(collect);
        supplierPayableBalanceDetailService.remove(wrapper);
    }

    //减去进货欠款记录
    @Override
    @Transactional
    public void subPayableBalance(Map<Long, BigDecimal> supplierIdrAndAmount) {
        for (Map.Entry<Long, BigDecimal> entry : supplierIdrAndAmount.entrySet()) {
            Long supplierId = entry.getKey();
            BigDecimal amount = entry.getValue();
            update(Wrappers.<Supplier>lambdaUpdate()
                    .setSql("payable_balance = payable_balance - " + amount)
                    .eq(Supplier::getId, supplierId)
            );
        }
    }

    //添加总的欠款
    @Override
    public void addPayableBalance(Map<Long, BigDecimal> supplierIdrAndAmount) {
        for (Map.Entry<Long, BigDecimal> entry : supplierIdrAndAmount.entrySet()) {
            Long supplierId = entry.getKey();
            BigDecimal amount = entry.getValue();
            if (amount.compareTo(BigDecimal.ZERO) == 0) continue;
            update(Wrappers.<Supplier>lambdaUpdate()
                    .setSql("payable_balance = payable_balance + " + amount)
                    .eq(Supplier::getId, supplierId)
            );
        }
    }

    //采购销售费用表的更新
    @Override
    @Transactional
    public void updatePayableBalanceDetails(List<Long> idList, List<SupplierPayableBalanceDetail> list) {
        if (!(idList == null) && !idList.isEmpty()) {
            LambdaQueryWrapper<SupplierPayableBalanceDetail> wrapper = Wrappers.<SupplierPayableBalanceDetail>lambdaQuery()
                    .eq(SupplierPayableBalanceDetail::getBillsType, list.get(0).getBillsType())
                    .in(SupplierPayableBalanceDetail::getBillId, idList);
            List<SupplierPayableBalanceDetail> payableBalanceDetails = supplierPayableBalanceDetailService.list(wrapper);
            supplierPayableBalanceDetailService.remove(wrapper);
            Map<Long, BigDecimal> collect = payableBalanceDetails.stream()
                    .collect(Collectors.groupingBy(SupplierPayableBalanceDetail::getSupplierId,
                            Collectors.mapping(
                                    SupplierPayableBalanceDetail::getPayableBalance,      // 提取退款金额
                                    Collectors.reducing(BigDecimal.ZERO, BigDecimal::add) // 聚合求和
                            )
                    ));
            subPayableBalance(collect);
        }
        addPayableBalanceDetails(list);
    }

    //更新欠款记录
    @Override
    @Transactional
    public void updatePayableBalanceDetails(SupplierPayableBalanceDetail payableBalance) {
        removePayableBalanceDetails(List.of(payableBalance.getBillId()), payableBalance.getBillsType());
        addPayableBalanceDetails(payableBalance);
    }

    @Override
    public void setStatus(List<Long> longs, int status) {
        update(Wrappers.<Supplier>lambdaUpdate()
                .set(Supplier::getStatus, status)
                .in(Supplier::getId, longs));
    }

    @Override
    public JSONArray listOnly() {
        List<Supplier> supplierList = list();
        JSONArray res = new JSONArray();
        for (Supplier supplier : supplierList) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.putOnce("id", supplier.getId());
            jsonObject.putOnce("name", supplier.getSupplierName());
            res.add(jsonObject);
        }
        return res;
    }

    @Override
    public void checkSupplier(Long id) {
        Supplier byId = getById(id);
        if (byId == null || byId.getStatus() == 0) throw new BillsException(MessageConstant.SUPPLIER_NOT_AVAILABLE);
    }
}
